#include <iostream>
#include <stdint.h>
#include <functional>
#include <vector>
#include <unordered_map>
#include <memory>
#include <unistd.h>


//定时器任务对象作用是封装定时任务
using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;           //定时器任务对象id
    uint32_t _timeout;      //定时器任务超时时间
    TaskFunc _task_cb;      //定时器对象要执行的定时任务
    bool _canceled;         //取消定时任务，false表示不取消，true表示取消
    ReleaseFunc _release;   //删除TimerWheel中保存的定时器对象信息
public:
    TimerTask(uint64_t id,uint32_t delay,const TaskFunc& task_cb)
        :_id(id),_timeout(delay),_task_cb(task_cb),_canceled(false)
    {}

    void SetRelease(const ReleaseFunc& cb){ _release = cb; } //设置具体的Release回调
    void Cancel(){_canceled = true; }
    int DelayTime() {return _timeout;}

    ~TimerTask()
    {
        if(_canceled == false) _task_cb();
        _release();
    }
};

//时间轮
//是通过shared_ptr来管理定时器任务对象 
class TimerWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;
    //注意成员定义的顺序，成员被初始化看的是定义顺序而不是初始化列表中的顺序
    //这里就踩了坑
    int _tick;      //当前时间轮的秒针，走到哪里释放哪里，就是通过调用shard_ptr来执行该位置的定时器任务
    int _capacity;  //轮盘最大数量，其实就是最大延迟时间。
    std::vector<std::vector<PtrTask>> _wheel; //时间轮(保存的每个对象都是shared_ptr)
    std::unordered_map<uint64_t,WeakTask> _timers; // 所有的定时器任务对象
    //当定时器任务对象真的要释放时，WeakTask也要释放

    int _timefd; //定时器描述符
    
private:
    void RemoveTimer(uint64_t id) //注意类内成员函数的第0个参数都是this指针
    {
        auto it = _timers.find(id);
        if(it != _timers.end())
        {
            _timers.erase(it);
        }

    }

public: 
    TimerWheel() :_tick(0),_capacity(60),_wheel(_capacity){}
    void TimerAdd(uint64_t id, uint32_t delay,const TaskFunc& task_cb) //添加定时任务
    {
        PtrTask pt(new TimerTask(id,delay,task_cb));     //1.为定时任务设置shared_ptr管理
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id));  //2.为定时任务设置完成后释放回调函数
                                //必须加&以及类名
        int pos = (_tick + delay) % _capacity;           
        _wheel[pos].push_back(pt);                       //3.将shared_ptr添加进时间轮
        _timers[id] = WeakTask(pt);                      //4.构造weak_ptr加入哈希表进行管理
    }   
    
    void TimerRefresh(uint64_t id)  //刷新定时任务,如果在TimerAdd里指定的添加定时任务的延时时间是5s，那么刷新定时任务后，还是延时5秒才销毁
    {
        //通过保存对象的weak_ptr来构造一个shared_ptr，并添加到轮子中
        auto it = _timers.find(id);
        if(it == _timers.end())
            return ;
        PtrTask pt = it->second.lock(); // lock:获取该weak_ptr管理对象的shared_ptr
        int delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }

    //秒针滴答滴答往后走
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();              //秒针走到哪里，就会把vector中所有管理定时器任务对象的share_ptr都释放。
    }
    
    //取消定时任务
    void TimerCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return ;
        PtrTask pt = it->second.lock(); //获取weak_ptr对应的shared_ptr;
        if(pt) pt->Cancel();
    }

};

//测试类
class Test
{
public:
    Test()
    {
        std::cout << "Test的构造函数" << std::endl;
    }
    
    ~Test()
    {
        std::cout << "Test的析构函数" << std::endl;
    }
};

void DelTest(Test* t)
{
    delete t;
}

int main()
{
    TimerWheel tw;
    Test* t = new Test();
    tw.TimerAdd((uint64_t)888, 5, std::bind(DelTest,t));
    
    for(int i = 0; i< 5;i++)
    {
        sleep(1);
        tw.TimerRefresh(888); //给id为888的定时任务对象刷新
        tw.RunTimerTask();    //秒针往后走
        std::cout << "刷新了一下定时任务，5秒后销毁定时器" << std::endl;
    }
    tw.TimerCancel(888);
    while(1)
    {
        std::cout << "-----------------------"  <<std::endl;
        sleep(1);
        tw.RunTimerTask();
    }
    return 0;
}